﻿using System;
using System.Collections.Generic;

using System.Linq;
using System.Security.Claims;
namespace DX.Security
{
  
    public class AbacAccessControlManager: IACL
    {
        private readonly ISecurityProvider databaseProvider;
        private readonly ICacheProvider _cache;
    /*
        public static AbacAccessControlManager Sqlite(string dbconnection, ICacheProvider cache)
        {
            return new AbacAccessControlManager(new SqliteDatabaseProvider(dbconnection), cache);
        }
        public static AbacAccessControlManager Sqlite(string dbconnection)
        {
            return Sqlite(dbconnection, HybridCacheProvider.Defalut());
        }*/
        public AbacAccessControlManager(ISecurityProvider databaseProvider, ICacheProvider cache)
        {
            this.databaseProvider = databaseProvider;
            _cache = cache;
        }


        // 获取策略（含缓存机制）
        internal IList<AbacPolicy> GetPolicies()
        {
            if (!_cache.TryGet("AbacPolicies", out IList<AbacPolicy> policies))
            {
                policies = databaseProvider.GetPolicies();
                _cache.Set("AbacPolicies", policies, TimeSpan.FromMinutes(10));
            }
            return policies;
        }

        // 检查访问权限（增强动作与资源关联）
        public bool CheckAccess(AccessRequest request)
        {
            var policies = GetPolicies();
            foreach (var policy in policies)
            {
                if (IsSubjectClaimMatch(request.Subject.Identity.Claims, policy.SubjectClaims) &&
                    IsResourceClaimMatch(request.Resource, policy.ResourceClaims) &&
                    request.Action == policy.Action &&
                    request.Resource.AllowedActions.Contains(request.Action))
                {
                    return policy.IsAllowed;
                }
            }
            return false;
        }

        // 主体属性匹配
        internal bool IsSubjectClaimMatch(IEnumerable<Claim> subjectClaims, IEnumerable<Claim> policyClaims)
        {
            return policyClaims.All(policyClaim =>
                subjectClaims.Any(subjectClaim =>
                    subjectClaim.Type == policyClaim.Type &&
                    subjectClaim.Value == policyClaim.Value));
        }
        // 资源属性匹配
        internal bool IsResourceClaimMatch(ResourceDescriptor resource, IEnumerable<Claim> policyClaims)
        {
            return policyClaims.All(policyClaim =>
                resource.HasClaim(policyClaim.Type, policyClaim.Value));
        }
    }


}